package ai4games_tests.soccer;

import game2dai.World;
import game2dai.entities.BaseEntity;
import game2dai.fsm.Dispatcher;
import game2dai.fsm.State;
import game2dai.fsm.Telegram;
import game2dai.maths.Vector2D;

public class PlayerKickBall extends State implements Constants {


	private static PlayerKickBall instance = null;

	public static PlayerKickBall state(){
		if(instance == null){
			instance = new PlayerKickBall();
			instance.name = "Kick ball";
		}
		return instance;
	}

	@Override
	public void enter(BaseEntity owner) {
		PlayerBase player = (PlayerBase) owner;
		// Make everyone know this is the controlling player
		player.team.setControllingPlayer(player);
		// If we are not ready to kick then change to ChaseBall state
		if(!player.team.pitch.ball.readyToBeKickedBy(player))
			player.FSM().changeState(PlayerChaseBall.state());
	}

	@Override
	public void execute(BaseEntity owner, double deltaTime, World world) {
		PlayerBase player = (PlayerBase) owner;
		Ball ball = player.team.pitch.ball;
		Vector2D ballPos = ball.pos();

		// Calculate the normalised vector to the ball
		Vector2D toBall = Vector2D.sub(ballPos, player.pos());
		toBall.normalize();
		// Calculate the dot product of the heading and toball vector
		double dot = player.heading().dot(toBall);

		// If there is a receiving player assigned or the ball is in the hands
		// of a goalkeeper or the player is facing away from the ball 
		// change to ChaseBall state.
		if(player.team.getReceivingPlayer() != null || player.team.pitch.ball.keeperHasBall() || dot < 0){
			player.FSM().changeState(PlayerChaseBall.state());
			return;
		}

		// See if we have a shot at goal
		double power = (0.6 + 0.4 * dot) * MaxShootingForce;
		Vector2D ballTarget = new Vector2D(); // populate this with the shot target
		// The probability of a shot increases as we get closer to opponents goal
		double prob = player.isInHotRegion() ? 0.8 : player.isInHotHalf() ? 0.6 : 0.05;
		if( Math.random() < prob && player.team.canShoot(ballPos, power, ballTarget)){
			player.team.addNoiseToKick(ballPos, ballTarget);
			Vector2D kickDirection = Vector2D.sub(ballTarget, ballPos);
			ball.kick(player, kickDirection, power);
			player.FSM().changeState(PlayerWait.state());
			player.findSupport();
			return;
		}
		
		// Attempt to pass the ball if we are threatened and a suitable receiver can be found
		power = (0.4 + 0.6 * dot) * MaxPassingForce;
		if (player.isThreatened()){
			PlayerBase receiver = player.team.findBestPass(player, ballTarget, power, FielderMinPassDistance);
			if(receiver != null){
				player.team.addNoiseToKick(ballPos, ballTarget);
				Vector2D kickDirection = Vector2D.sub(ballTarget, ballPos);
				ball.kick(player, kickDirection, power);
				Dispatcher.dispatch(0, player.ID(), receiver.ID(), RECEIVE_BALL, ballTarget);
				player.FSM().changeState(PlayerWait.state());
				player.findSupport();
				return;
			}
		}
		// Either we are not threatened or if threatened unable to find a suitable pass
		// so dribble
		player.findSupport();
		player.FSM().changeState(PlayerDribble.state());
	}

	@Override
	public void exit(BaseEntity owner) {
	}

	@Override
	public boolean onMessage(BaseEntity owner, Telegram tgram) {
		return false;
	}

}
